/*
    webpack.config.js webpack的配置文件
    作用：指示webpack干哪些活（当你运行webpack指令时，会加载里面的配置）

    所有构建工具都是基于nodejs平台运行的～模块化默认采用commonjs

    loader: 1.下载 2.使用（配置loader）
    plugin：1.下载 2.引入 3.使用

    开发环境配置：能让代码运行
        运行项目指令：
            webpack会将打包结果输出出去
            npx webpack-dev-server 只会在内存中编译打包，没有输出

*/
// resolve 用来拼接绝对路径的方法
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

// 设置nodejs环境变量：决定使用browserlist的哪个环境，不写默认生产环境
// process.env.NODE_ENV='development';

/*
   HMR: hot module replacement 
   作用：一个模块发生变化，只能重新打包这一个模块（而不是打包多有模块）
        极大提升构建速度
        // 开启HMR功能  当修改了webpack配置要想生效，必须重启webpack服务
        hot: true 
    
    样式文件：可以使用HMR功能：因为style-loader内部实现了～
    js文件：默认不能使用HMR功能-->需要修改js代码，添加支持HMR功能的代码
        注意：HMR功能对js的处理，只能处理非入口js文件的其他文件。
    html文件：默认不能使用HMR功能，同时会导致问题：html文件不能热更新了～（不用做HMR功能）
        解决：修改entry入口，将html文件引入
         entry: ['./src/js/index.js', './pubilc/index.html']

    source-map：一种提供源代码到构建后代码映射技术（如果构建后代码出错了，通过映射可以追踪源代码错误）
    devtool: 'source-map'
    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

    内联和外部的区别：1.外部生成了文件，内联没有 2.内联构建速度更快
    source-map: 外部 错误代码准确信息 和 源代码的错误位置
    inline-source-map: 内联  只生成一个内联sourch-map；错误代码准确信息 和 源代码的错误位置
    hidden-source-map: 外部  错误代码错误原因，但是没有错误位置，不能追踪到源代码错误，只能提示到构建后代码的错误位置
    eval-source-map: 内联  每一个文件都生成对应的sourch-map，都在eval   错误代码准确信息 和 源代码的错误位置，多一个hash值
    nosources-source-map: 外部  错误代码准确信息，但是没有任何源代码信息
    cheap-source-map: 外部  错误代码准确信息 和 源代码的错误位置，只能精确到行
    cheap-module-source-map: 外部 错误代码准确信息 和 源代码的错误位置，module会将loader的source map加入

    开发环境L：速度快，调试更友好
        速度快（eval>inline>cheap>...）eval-cheap-source-map  eval-source-map
        调试更友好 source-map cheap-module-source-map cheap-source-map

        --> eval-source-map  eval-cheap-module-source-map
    生产环境：源代码要不要隐藏？调试要不要更友好
        内联会让代码体积变大，所以在生产环境不用内联
        源代码隐藏
        nosources-source-map 全部隐藏
        hidden-source-map 只隐藏源代码，会提示构建后代码错误信息
        调试更友好
        source-map
        --> source-map cheap-module-source-map
*/


const commonCssLoader = [
    MiniCssExtractPlugin.loader,
    'css-loader',
    {
        // 还需要在package.js中定义browerslist
        loader: 'postcss-loader',
        options: {
            ident: 'postcss',
            plugins: ()=>[
                require('postcss-preset-env')()
            ]
        }
    }
];

module.exports = {
    // webpack配置
    // 入口起点
    entry: './src/js/index.js',
    // 输出
    output: {
        // 输出文件名
        filename: 'js／built.[contenthash:10].js',
        // 输出路径
        // __dirname nodejs的变量，代表当前文件的目录绝对路径
        path: resolve(__dirname, 'build')
    },
    // loader的配置
    module: {
        rules: [
            // 详细loader配置
            // 不同文件必须配置不同loader处理
            {
                // 匹配哪些文件
                test: /\.css$/,
                // 使用哪些loader进行处理
                use: [
                    // user数组中loader执行顺序：从右到左，从下到上 依次进行
                    // 创建style标签，将js中的样式资源插入进行，添加到head中生效
                    // 'style-loader',
                    // * 这个loader取代style-loader 作用：提取js中css成单独文件
                    // MiniCssExtractPlugin.loader,
                    // 将css文件变成commonjs模块加载js中，里面内容是样式字符串
                    // 'css-loader',
                    ...commonCssLoader,
                    /*
                        css 兼容性处理: postcss-->postcss-loader postcss-preset-env
                        postcss-preset-env作用：帮postcss找到package.json中browserslist里面的配置，通过配置加载指定的css兼容性样式
                        "browserslist": {
                            "development": [ // 开发环境->设置node环境变量：process.env.NODE_ENV=development
                                "last 1 chrome version",
                                "last 1 firefox version",
                                "last 1 safari version"
                            ],
                            "production": [ // 生产环境：默认是看生产环境
                                ">0.2%",
                                "not dead",
                                "not op_mini all"
                            ]
                        }
                        // 使用loader的默认配置
                        // 'postcss-loader',
                        // 修改loader的配置
                    */ 
                   {
                       loader: 'postcss-loader',
                       options: {
                           ident: 'postcss',
                           plugins: ()=>[
                               // postcss的插件
                               require('postcss-preset-env')()
                           ]
                       }
                   }
                ]
            },
            {
                // 匹配哪些文件
                test: /\.less$/,
                // 使用哪些loader进行处理
                // 要使用多个loader处理用use
                use: [
                    // user数组中loader执行顺序：从右到左，从下到上 依次进行
                    // 创建style标签，将js中的样式资源插入进行，添加到head中生效
                    // 'style-loader',
                    // 将css文件变成commonjs模块加载js中，里面内容是样式字符串
                    // 'css-loader',
                    // *如果使用less需要做兼容性处理的话要写在这里
                    ...commonCssLoader,
                    // 将less文件编译成css文件, 需要下载less和less-loader
                    'less-loader'
                ]
            },
            {
                // 问题：默认处理不了html中img图片
                // 处理图片资源
                test: /\.(jpg|jpeg|png|gif)/,
                // 使用一个loader
                // 下载url-loader file-loader
                loader: 'url-loader',
                options: {
                    // 图片大小小于8kb,就会被base64处理  8~12
                    // 优点：减少请求数量（减轻服务器压力）
                    // 缺点：图片体积会更大（文件请求速度更慢）
                    limit: 10 * 1024,
                    // 问题：因为url-loader默认使用es6模块化解析，而html-loader引入图片是commonjs
                    // 解析时会出问题：[object Moudle]
                    // 解决：关闭url-loader的es6模块化，使用commonjs解析
                    esModule: false, // 可能版本问题，不设置也没有报错
                    // 给图片进行重命名
                    // [hash:10]取图片的hash的前10位
                    // [ext]取文件原来的扩展名
                    name: '[hash:10].[ext]',
                    outputPath: 'images'
                }
            },
            {
                test: /\.html$/,
                // 处理html文件的img图片（负责引入img，从而能被url-loader进行处理）
                loader: 'html-loader'
            },
            {
                // 打包其他资源（除了html/js/css资源以外的资源）
                exclude: /\.(css|less|js|json|html|jpg|jpeg|png|gif)$/,
                loader: 'file-loader',
                options: {
                    name: '[hash:10].[ext]',
                    outputPath: 'media'
                }
            },
            // {
                /*
                    语法检查：eslint-loader eslint
                    注意：只检查自己写的源代码，第三方的库是不用检查的
                    *设置检查规则：package.json中eslintConfig中设置～
                    "eslintConfig": {
                        "extends": "airbnb-base"
                    }
                    推荐使用airbnb规则-->eslint-config-airbnb-base(without react plugins)  eslint-plugin-import eslint
                
                    正常来讲，一个文件只能被一个loader处理。
                    当一个文件要被多个loader处理，那么一定要指定loader执行的先后顺序：先执行eslint 再执行babel
                */
            //    test: /\.js$/,
            //    exclude: /node_modules/,
            //    enforce: 'pre', // *优先执行
            //    loader: 'eslint-loader',
            //    options: {
            //         // 自动修复eslint的错误
            //         fix: true
            //    }
            // },
            {
                /*
                    js兼容性处理: babel-loader @babel/core @babel/preset-env
                        1.基本js兼容性处理 --> @babel/preset-env
                            问题：只能转换基本语法，如promise高级语法不能转换
                        2.全部js兼容性处理 --> @babel/polyfill
                            问题：我只要解决部分兼容性问题，但是将所有兼容性代码全部引入，体积太大～
                        3.需要做兼容性处理的就做：按需加载 --> core-js

                        使用第三中就将第二种注释
                */
               test: /\.js$/,
               exclude: /node_modules/,
               loader: 'babel-loader',
               options: {
                    // 预示：指示babel做怎么样的兼容性处理
                    // presets: ['@babel/preset-env']  // js中引入：import '@babel/polyfill'; 
                   presets: [
                    [
                        '@babel/preset-env',
                        {
                            // 按需加载
                            useBuiltIns: 'usage',
                            // 指定core-js版本
                            corejs: {
                                version: 3
                            },
                            // 指定兼容性做到哪个版本浏览器
                            targets: {
                                chrome: '60',
                                firefox: '50',
                                ie: '9',
                                safari: '10',
                                edge: '17'
                            }
                        }
                    ]
                   ],
                   // 开启babel缓存
                    // 第二次构建时，会读取之前的缓存
                    cacheDirectory: true    
               }
            }
        ]
    },
    plugins: [
        // 详细plugins配置
        // html-webpack-plugin
        // 功能：默认会创建一个空的html，自动引入打包输出的所有资源（js／css）
        // 需求：需要有结构的html文件
        new HtmlWebpackPlugin({
            // 复制'./src/index.html' 文件，并自动引入打包输出的所有资源（js／css）
            template: './public/index.html',
            // template: './src/index.html',
            minify: { // 压缩html代码
                collapseWhitespace: true, // 移除空格
                removeComments: true, // 移除注释
            }
        }),
        new MiniCssExtractPlugin({
            // 对输出的css文件进行重命名
            filename: 'css/built.[contenthash:10].css'
        }),
        // 压缩css
        new OptimizeCssAssetsWebpackPlugin()
    ],
    // 模式
    mode: 'development', // 开发模式
    // mode: 'production', // 生产环境下会自动压缩js代码
    // 开发服务器devServer：用来自动化（自动编译，自动刷新浏览器）
    // 特点：只会在内存中编译打包，不会有任何输出
    // 启动devServer指令为：npx webpack-dev-server
    devServer: {
        // 项目构建后的路径
        contentBase: resolve(__dirname, 'build'), 
        // 启动gzip压缩
        compress: true,
        port: 3000, // 端口号
        open: true, // 自动打开浏览器
        // 开启HMR功能  当修改了webpack配置要想生效，必须重启webpack服务
        hot: true 
    },
    // devtool: 'source-map'
}